/*******************************************************************************
* @file    fvi2c_master.c
* @author  Fins
* @brief   I2c master core file
* @time    2020-10-22 20:23:40 Thursday
* @codeing UTF-8
* @license
*     Copyright 2020 Fins
*
*     Licensed under the Apache License, Version 2.0 (the "License");
*     you may not use this file except in compliance with the License.
*     You may obtain a copy of the License at
*
*         http://www.apache.org/licenses/LICENSE-2.0
*
*     Unless required by applicable law or agreed to in writing, software
*     distributed under the License is distributed on an "AS IS" BASIS,
*     WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
*     See the License for the specific language governing permissions and
*     limitations under the License.
* @verbatim
================================================================================
                        ##### xxxxxxxxxxxxxxxxxxxxxxx #####
================================================================================
* @endverbatim
* @attention
*******************************************************************************/



/* Includes start *************************************************************/
/*     Lib files ****************************** */
#include "fvi2c_master.h"
#include "fvi2c_mas_signal.h"
/*     User files ***************************** */


/* Includes end ***************************************************************/

/* Define start ***************************************************************/



/* Define end *****************************************************************/

/* Typedef start **************************************************************/



/* Typedef end ****************************************************************/

/* Global variable start ******************************************************/



/* Global Variable end ********************************************************/

/* Static function declaration start ******************************************/



/* Static function declaration end ********************************************/

/* function start *************************************************************/

/**
  * @brief      Transmit byte
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[in]  byte: One byte data
  * @retval     Refer 'f_vi2cRetStat_e'
  */
static fvi2c_ret_e Fvi2cMasTByte(fvi2c_s* vi2cP, fuint8 byte)
{
    fvi2c_ret_e ret = FVI2C_ROK;
    fuint8 bit = 0;
    fuint8 ack = 0;

    for(fuint8 i = 0; i < 8; i++)
    {
        bit = byte >> 7;
        ret = Fvi2cMasTBit(vi2cP,bit);
        if(ret != FVI2C_ROK) return ret;
        byte <<= 1;
    }
    ret = Fvi2cMasRBit(vi2cP,&ack);
    if(ret != FVI2C_ROK) return ret;

    if(ack)
        return FVI2C_RNACK;
    else 
        return FVI2C_ROK;
}



/**
  * @brief      Recieve byte
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[in]  ack: ACK status FVI2C_ACK/FVI2C_NACK
  * @param[out] byte: One byte data
  * @retval     Refer 'f_vi2cRetStat_e'
  */
static fvi2c_ret_e Fvi2cMasRByte(fvi2c_s* vi2cP, fvi2c_ack_e ack, fuint8* byte)
{
    fvi2c_ret_e ret = FVI2C_ROK;
    fuint8 bit = 0;

    for(fuint8 i = 0; i < 8; i++)
    {
        *byte <<= 1;
        ret = Fvi2cMasRBit(vi2cP,&bit);
        if(ret != FVI2C_ROK) return ret;
        *byte |= bit;
    }
    ret = Fvi2cMasTBit(vi2cP,ack);
    if(ret != FVI2C_ROK) return ret;

    return FVI2C_ROK;
}



/**
  * @brief      Transmit bytes
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[in]  bytes: datas
  * @param[in]  bytes: Number of byte
  * @retval     Refer 'f_vi2cRetStat_e'
  */
static fvi2c_ret_e Fvi2cMasTBytes(
    fvi2c_s* vi2cP,
    fvi2c_flag_e flags,
    const fuint8 bytes[],
    fuint32 bytesNum)
{
    fvi2c_ret_e ret = FVI2C_ROK;

    for(fuint32 i = 0; i < bytesNum; i++)
    {
        ret = Fvi2cMasTByte(vi2cP,bytes[i]);
        if(!(flags & FVI2C_IGNORE_NACK) && (ret != FVI2C_ROK)) return ret;
    }
    
    return FVI2C_ROK;
}



/**
  * @brief      Transmit bytes
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[in]  readNum: Read bytes number
  * @param[in]  buffSize: Buffer size
  * @param[out] buff: Read data buffer
  * @retval     Refer 'f_vi2cRetStat_e'
  */
static fvi2c_ret_e Fvi2cMasRBytes(
    fvi2c_s* vi2cP,
    fvi2c_flag_e flags,
    fuint32 readNum,
    fuint32 buffSize,
    fuint8 buff[])
{
    fvi2c_ret_e ret = FVI2C_ROK;
    fvi2c_ack_e ackSta = FVI2C_ACK;
    fuint32 currentReadNum;
    const fuint32 ackReadBytesNum = readNum - 1;

    /* NACK when read ? */
    if(flags & FVI2C_READ_NACK)
        ackSta = FVI2C_NACK;

    for(currentReadNum = 0; currentReadNum < ackReadBytesNum;)
    {
        ret = Fvi2cMasRByte(vi2cP,ackSta,&buff[(currentReadNum)++]);
        if(ret != FVI2C_ROK) return ret;
    }
    ret = Fvi2cMasRByte(vi2cP,FVI2C_NACK,&buff[(currentReadNum)++]);
    if(ret != FVI2C_ROK) return ret;

    return ret;
}



/**
  * @brief      Format address 
  * @param[in]  iAddr: in address
  * @param[in]  flag: masssage flags
  * @param[out] oAddr1: Addr byte 1
  * @param[out] oAddr2: Addr byte 2
  * @retval     Refer 'f_vi2cRetStat_e'
  */
F_INLINE fvi2c_ret_e Fvi2cMasAddrFormat(
    fuint16 iAddr,
    fvi2c_flag_e flags,
    fuint8* oAddr1,
    fuint8* oAddr2)
{
    if(flags & FVI2C_10B_ADDR) /**< 10 bit address */
    {
        *oAddr1 = ((iAddr >> 8) & 0x07) | 0xF0;
        *oAddr2 = iAddr;
    }
    else                      /**< 8 bit address  */
        *oAddr1 = iAddr;
    if(flags & FVI2C_OLADDR)
    {
        if(flags & FVI2C_READ) /**< Read */
            *oAddr1 |= 1U;
        else                  /**< Write */
            *oAddr1 &= ~1U;
    }
    return FVI2C_ROK;
}



/**
  * @brief      Transmit address
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[in]  flag: masssage flags
  * @param[in]  iAddr1: Addr byte 1
  * @param[in]  iAddr1: Addr byte 2
  * @retval     Refer 'f_vi2cRetStat_e'
  */
static fvi2c_ret_e Fvi2cMasTAddr(fvi2c_s* vi2cP, 
    fvi2c_flag_e flags,
    fuint8 iAddr1,fuint8 iAddr2)
{
    fvi2c_ret_e ret = FVI2C_ROK;
    if(flags & FVI2C_10B_ADDR)
    {
        ret = Fvi2cMasTByte(vi2cP,iAddr1);
        if(!(flags & FVI2C_IGNORE_NACK) && (ret != FVI2C_ROK)) return ret;
        ret = Fvi2cMasTByte(vi2cP,iAddr2);
        if(!(flags & FVI2C_IGNORE_NACK) && (ret != FVI2C_ROK)) return ret;
    }
    else
    {
        ret = Fvi2cMasTByte(vi2cP,iAddr1);
        if(!(flags & FVI2C_IGNORE_NACK) && (ret != FVI2C_ROK)) return ret;
    }
    return FVI2C_ROK;
}



/**
  * @brief      Transfer massages
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[in]  msgs: Massage
  * @param[in]  num: Massage number
  * @retval     Refer 'f_vi2cRetStat_e'
  */
fvi2c_ret_e Fvi2cMasTransfer(fvi2c_s* vi2cP, fuint32 num, fvi2c_msg_s msgs[])
{
    FVI2C_ASSERT(vi2cP != F_NULL);
    FVI2C_ASSERT(vi2cP->interface != F_NULL);
    FVI2C_ASSERT(vi2cP->interface->GetPin != F_NULL);
    FVI2C_ASSERT(vi2cP->interface->SetPin != F_NULL);
    FVI2C_ASSERT(vi2cP->interface->UnitDelay != F_NULL);
    FVI2C_ASSERT(msgs != F_NULL);

    fvi2c_ret_e ret = FVI2C_ROK;
    fuint8 addrByte1 = 0;
    fuint8 addrByte2 = 0;

    ret = Fvi2cMasTStaSig(vi2cP);
    if(ret != FVI2C_ROK) return ret;
    for(fuint32 i = 0; i < num; i++)
    {
        if(msgs[i].len == 0) {Fvi2cMasTStopSig(vi2cP); continue;}  
        FVI2C_ASSERT(msgs[i].msg != F_NULL);
        /* Addr handle */
        Fvi2cMasAddrFormat(msgs[i].addr, msgs[i].flags, &addrByte1, &addrByte2);

        if(addrByte1 & 1U)   
        {
            ret = Fvi2cMasTAddr(vi2cP, msgs[i].flags, addrByte1, addrByte2);
            if(ret != FVI2C_ROK) {Fvi2cMasTStopSig(vi2cP); return ret;}
            ret = Fvi2cMasRBytes(vi2cP,
                msgs[i].flags,
                msgs[i].len,msgs[i].len,
                msgs[i].msg);
            if(ret != FVI2C_ROK) {Fvi2cMasTStopSig(vi2cP); return ret;}
        }else
        {
            ret = Fvi2cMasTAddr(vi2cP, msgs[i].flags, addrByte1, addrByte2);
            if(ret != FVI2C_ROK) {Fvi2cMasTStopSig(vi2cP); return ret;}
            ret = Fvi2cMasTBytes(vi2cP,msgs[i].flags,msgs[i].msg,msgs[i].len);
            if(ret != FVI2C_ROK) {Fvi2cMasTStopSig(vi2cP); return ret;}
        }
        if (i < (num - 1))
        {
            ret = Fvi2cMasTRestaSig(vi2cP);
            if(ret != FVI2C_ROK) {Fvi2cMasTStopSig(vi2cP); return ret;}
        }else
        {
            ret = Fvi2cMasTStopSig(vi2cP);
            if(ret != FVI2C_ROK) return ret;
        }
    }
    return FVI2C_ROK;
}



/**
  * @brief      Attach low level interface
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[in]  lLIf: low level interface
  * @retval     Refer 'f_vi2cRetStat_e'
  */
fvi2c_ret_e Fvi2cAttachIf(fvi2c_s* vi2cP, const fvi2c_lLIf_s* lLIf)
{
    FVI2C_ASSERT(vi2cP != F_NULL);
    FVI2C_ASSERT(lLIf != F_NULL);
    FVI2C_ASSERT(lLIf->GetPin != F_NULL);
    FVI2C_ASSERT(lLIf->SetPin != F_NULL);
    FVI2C_ASSERT(lLIf->UnitDelay != F_NULL);
    
    vi2cP->interface.GetPin = lLIf->GetPin;
    vi2cP->interface.SetPin = lLIf->SetPin;
    vi2cP->interface.UnitDelay = lLIf->UnitDelay;
    return FVI2C_ROK;
}



/**
  * @brief      Attach low level interface
  * @param[in]  vi2c: Virtual I2C instance pointer
  * @param[in]  lLIf: low level interface
  * @retval     Refer 'f_vi2cRetStat_e'
  */
fvi2c_ret_e Fvi2cConfig(fvi2c_s* vi2cP, const fvi2c_conf_s* conf)
{
    FVI2C_ASSERT(vi2cP != F_NULL);
    FVI2C_ASSERT(conf != F_NULL);
    
    vi2cP->conf.chgPerTime = conf->chgPerTime;
    vi2cP->conf.chgPosTime = conf->chgPosTime;
    vi2cP->conf.holdPerTime = conf->holdPerTime;
    vi2cP->conf.holdPosTime = conf->holdPosTime;
    return FVI2C_ROK;
}
/* function end ***************************************************************/

////////////////////////////////- END OF FILE  -////////////////////////////////
